﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;

namespace BtLibs
{
    public interface XmlSerializable
    {
        void ToNode(XmlNode node);
        void FromNode(XmlNode node);
    }

    public static class XmlUtility
    {
        public static XmlElement AppendValueElement(XmlNode parent, string name, string value, bool cdata = false)
        {
            XmlElement ele = AppendElement(parent, name);
            if (!cdata)
            { ele.InnerText = value; }
            else
            { ele.AppendChild(parent.OwnerDocument.CreateCDataSection(value)); }
            return ele;
        }
        public static XmlElement AppendValueElements(XmlNode parent, string eleNodeName, string valueNodeName, List<string> values, bool cdata = false)
        {
            if (parent == null) { return null; }
            if (string.IsNullOrEmpty(eleNodeName) || string.IsNullOrEmpty(valueNodeName)) { return null; }
            if (values == null || values.Count <= 0) { return null; }
            XmlElement eleNode = AppendElement(parent, eleNodeName);
            foreach (string value in values)
            { AppendValueElement(eleNode, valueNodeName, value, cdata); }
            return eleNode;
        }
        public static string ReadNodeContent(XmlNode node, string defaultValue = "")
        {
            if (node == null) { return defaultValue; }
            if (node.ChildNodes.Count == 1 && node.ChildNodes[0].NodeType == XmlNodeType.CDATA)
            {
                XmlCharacterData cDataNode = node.ChildNodes[0] as XmlCharacterData;
                return cDataNode.InnerText;
            }
            else { return node.InnerXml; }
        }
        public static List<string> ReadNodeContents(XmlNode node, string childName, string defauleValue = "")
        {
            if (node == null) { return new List<string>(); }
            XmlNodeList nodes = node.SelectNodes(childName);
            if (nodes == null) { return new List<string>(); }
            List<string> values = new List<string>();
            foreach (XmlNode child in nodes)
            { values.Add(ReadNodeContent(child)); }
            return values;
        }
        public static XmlElement AppendElement(XmlNode parent, string name)
        {
            XmlElement ele = parent.OwnerDocument.CreateElement(name);
            parent.AppendChild(ele);
            return ele;
        }

        public static void WriteXmlFile(string file, string rootName, object data)
        {
            XmlSerializable serializable = data as XmlSerializable;
            if (serializable == null) { throw new Exception("cannot serializable. type=" + data.GetType().Name); }
            XmlDocument doc = new XmlDocument();
            XmlElement root = doc.CreateElement(rootName);
            serializable.ToNode(root);
            WriteXmlFile(file, root);
        }
        public static void WriteXmlFile(string file, XmlNode node)
        {
            FileInfo fileInfo = new FileInfo(file);
            if (!fileInfo.Directory.Exists)
            { fileInfo.Directory.Create(); }
            using (XmlWriter writer = XmlWriter.Create(file, DefaultXmlWriterSettings()))
            {
                node.WriteTo(writer);
                writer.Flush();
            }
        }
        public static XmlWriterSettings DefaultXmlWriterSettings()
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Encoding = Encoding.UTF8;
            settings.Indent = true;
            settings.IndentChars = "  ";
            settings.NewLineChars = "\n";
            return settings;
        }

        public static XmlElement Load(string filePath)
        {
            if (!File.Exists(filePath)) { return null; }
            XmlDocument doc = new XmlDocument();
            doc.Load(filePath);
            return doc.DocumentElement;
        }
    }
}
